package com.rambo.sdh.common.util;


import com.xiaoleilu.hutool.bean.DynaBean;
import com.xiaoleilu.hutool.date.DateTime;
import com.xiaoleilu.hutool.date.DateUtil;
import com.xiaoleilu.hutool.util.StrUtil;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.persistence.Column;
import javax.persistence.Entity;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 底层 dao 层工具
 * Create by Rambo on 2017/6/16
 **/
public class BaseDaoUtil {
    private final static Logger log = LoggerFactory.getLogger(BaseDaoUtil.class);

    /**
     * 重写底层父类的 findByExample 方法，解决当查询的 po 中含有日期属性时 Criteria 标准查询无法准确比较的问题
     *
     * @param session 数据源 session
     * @param po      含有日期字段的 PO
     * @param <T>     泛型 PO
     */
    @SuppressWarnings("unchecked")
    public static <T> List<T> findByExampleIncludeDate(Session session, Object po) {
        try {
            StringBuilder sql = new StringBuilder("SELECT * FROM ");
            sql.append(po.getClass().getAnnotation(Entity.class).name());
            sql.append(" WHERE 1=1 ");

            String property;
            Map<String, String> paramMap = new HashMap<>();
            for (Field field : po.getClass().getDeclaredFields()) {
                property = DynaBean.create(po).get(field.getName());
                if (StrUtil.isEmpty(property)) {
                    continue;
                }

                if (field.getType() == Date.class) {
                    sql.append(" AND TO_CHAR(");
                    sql.append(getPOTableColum(po, field.getName()));
                    sql.append(",'YYYY-MM-DD') = :");
                    sql.append(field.getName());

                    DateTime dateTime = DateUtil.parse(property, new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.ENGLISH));
                    paramMap.put(field.getName(), DateUtil.format(dateTime, "yyyy-MM-dd"));
                } else {
                    sql.append(" AND ");
                    sql.append(getPOTableColum(po, field.getName()));
                    sql.append(" = :");
                    sql.append(field.getName());
                    paramMap.put(field.getName(), property);
                }
            }
            log.info("sql:{},paramMap:{}", sql, paramMap);

            SQLQuery sqlQuery = session.createSQLQuery(sql.toString());
            sqlQuery.addEntity(po.getClass());
            for (Map.Entry<String, String> entry : paramMap.entrySet()) {
                sqlQuery.setParameter(entry.getKey(), entry.getValue());
            }
            return sqlQuery.list();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 通过反射获取数据库 PO,get 方法上的表字段注解
     *
     * @param po        待获取的 PO 对象
     * @param fieldName 字段名称
     */
    private static String getPOTableColum(Object po, String fieldName) throws NoSuchMethodException {
        Method method = po.getClass().getMethod("get" + StrUtil.upperFirst(fieldName));
        return method.getAnnotation(Column.class).name();
    }
}